package com.jy.rhin.application.assembler;

import cn.org.chiss.rhin._2015.base.Integer;
import cn.org.chiss.rhin._2015.base.*;
import cn.org.chiss.rhin._2015.base.document.*;
import cn.org.chiss.rhin._2015.base.object.*;
import cn.org.chiss.rhin._2015.document.repository.ProvideAndRegisterDocumentSet;
import com.alibaba.fastjson.JSON;
import com.jy.framework.base.utils.Converter;
import com.jy.rhin.sdk.constants.DateFormatPatternConstants;
import com.jy.rhin.sdk.dto.document.*;
import org.springframework.util.CollectionUtils;

import javax.xml.bind.annotation.XmlEnumValue;
import java.lang.String;
import java.lang.reflect.Field;
import java.util.*;
import java.util.Date;
import java.util.stream.Collectors;

/**
 * @Description: 文档存储转换
 * @Author: lww
 * @Date: 2022/6/1 10:50
 */
public class DocumentStorageAssembler {

    private DocumentStorageAssembler() {
    }

    public static DocumentProvideAndRegisterDto toDto(ProvideAndRegisterDocumentSet provideAndRegister) {
        DocumentProvideAndRegisterDto provideAndRegisterDto = new DocumentProvideAndRegisterDto();
        provideAndRegisterDto.setSubmissionSet(buildSubmissionSet(provideAndRegister.getSubmissionSet(), false));
        provideAndRegisterDto.setDocuments(buildDocument(provideAndRegister.getDocument()));
        return provideAndRegisterDto;
    }

    /**
     * 文档内容
     *
     * @param documentList
     * @return
     */
    private static List<DocumentContentDto> buildDocument(List<Document> documentList) {
        if (!CollectionUtils.isEmpty(documentList)) {
            List<DocumentContentDto> documentDtoList = new ArrayList<>();
            documentList.forEach(document -> {
                DocumentContentDto documentContentDto = new DocumentContentDto();
                documentContentDto.setId(getUriValue(document.getId()));
                documentContentDto.setContent(new String(Base64.getEncoder().encode(document.getContent())));
                documentDtoList.add(documentContentDto);
            });
            return documentDtoList;
        }
        return Collections.emptyList();
    }

    /**
     * 文档提交集信息
     *
     * @param submissionSet
     * @return
     */
    public static DocumentSubmissionSetDto buildSubmissionSet(SubmissionSet submissionSet, boolean entryToStr) {
        DocumentSubmissionSetDto submissionSetDto = new DocumentSubmissionSetDto();
        submissionSetDto.setId(getIdValue(submissionSet.getId()));
        submissionSetDto.setHomeCommunityId(getUriValue(submissionSet.getHomeCommunityId()));
        submissionSetDto.setSourceId(getOidValue(submissionSet.getSourceId()));
        submissionSetDto.setPatientDomain(getPatientIdValue(submissionSet.getPatientId()));
        submissionSetDto.setUniqueId(getOidValue(submissionSet.getUniqueId()));
        submissionSetDto.setSubmissionTime(dateTimeConvertDate(submissionSet.getSubmissionTime()));
        submissionSetDto.setContentTypeCode(convertConcept(submissionSet.getContentTypeCode()));
        List<RegObject> regObjectList = submissionSet.getFolderOrDocumentEntryOrAssociation();
        if (!CollectionUtils.isEmpty(regObjectList)) {
            List<DocumentFolderDto> folders = new ArrayList<>();
            List<DocumentEntryDto> entries = new ArrayList<>();
            List<DocumentAssociationDto> associations = new ArrayList<>();
            regObjectList.forEach(regObject -> {
                if (regObject instanceof Folder) {
                    folders.add(buildFolder((Folder) regObject));
                } else if (regObject instanceof DocumentEntry) {
                    entries.add(buildDocumentEntry((DocumentEntry) regObject, entryToStr));
                } else if (regObject instanceof Association) {
                    associations.add(buildAssociation((Association) regObject));
                }
            });
            submissionSetDto.setFolders(folders);
            submissionSetDto.setEntries(entries);
            submissionSetDto.setAssociations(associations);
        }
        return submissionSetDto;
    }

    /**
     * 文档关联信息
     *
     * @param association
     * @return
     */
    private static DocumentAssociationDto buildAssociation(Association association) {
        DocumentAssociationDto associationDto = new DocumentAssociationDto();
        associationDto.setId(getIdValue(association.getId()));
        associationDto.setStatusCode(getStatusCodeValue(association.getStatusCode()));
        associationDto.setTypeCode(getAssociationTypeValue(association.getTypeCode()));
        AssociationObject sourceObject = association.getSourceObject();
        if (Objects.nonNull(sourceObject)) {
            associationDto.setSourceId(getUriValue(sourceObject.getId()));
            associationDto.setSourceStatus(getAssociationStatusValue(sourceObject.getStatus()));
        }
        AssociationObject targetObject = association.getTargetObject();
        if (Objects.nonNull(targetObject)) {
            associationDto.setTargetId(getUriValue(targetObject.getId()));
            associationDto.setTargetStatus(getAssociationStatusValue(targetObject.getStatus()));
        }
        return associationDto;
    }

    /**
     * 文档条目
     *
     * @param entry
     * @return
     */
    private static DocumentEntryDto buildDocumentEntry(DocumentEntry entry, boolean entryToStr) {
        DocumentEntryDto entryDto = new DocumentEntryDto();
        entryDto.setId(getIdValue(entry.getId()));
        entryDto.setTitle(getStringValue(entry.getTitle()));
        entryDto.setFormatCode(getCodeValue(entry.getFormatCode()));
        entryDto.setPatientDomain(getPatientIdValue(entry.getPatientId()));
        entryDto.setPatientInfo(getPatientInfo(entry.getSourcePatientInfo()));
        entryDto.setServiceStartTime(dateTimeConvertDate(entry.getServiceStartTime()));
        entryDto.setServiceStopTime(dateTimeConvertDate(entry.getServiceStopTime()));
        entryDto.setCreationTime(dateTimeConvertDate(entry.getCreationTime()));
        entryDto.setStatusCode(getStatusCodeValue(entry.getStatusCode()));
        entryDto.setUniqueId(getOidValue(entry.getUniqueId()));
        entryDto.setSize(getIntegerValue(entry.getSize()));
        entryDto.setHash(getStringValue(entry.getHash()));
        entryDto.setRepositoryUniqueId(getOidValue(entry.getRepositoryUniqueId()));
        entryDto.setHomeCommunityId(getOidValue(entry.getHomeCommunityId()));
        entryDto.setClassCode(convertConcept(entry.getClassCode()));
        entryDto.setLanguageCode(getCodeValue(entry.getLanguageCode()));
        entryDto.setMimeType(getStringValue(entry.getMimeType()));
        entryDto.setConfidentialityCode(convertCoding(entry.getConfidentialityCode()));
        entryDto.setEventCode(convertConceptList(entry.getEventCode()));
        entryDto.setHealthcareFacilityTypeCode(convertConcept(entry.getHealthcareFacilityTypeCode()));
        entryDto.setPracticeSettingCode(convertConcept(entry.getPracticeSettingCode()));
        entryDto.setTypeCode(convertConcept(entry.getTypeCode()));
        entryDto.setLanguageCode(getCodeValue(entry.getLanguageCode()));
        entryDto.setMimeType(getStringValue(entry.getMimeType()));
        if (Objects.nonNull(entry.getAuthor()) && !CollectionUtils.isEmpty(entry.getAuthor().getAuthorInstitution())) {
            List<Reference> authorInstitutionList = entry.getAuthor().getAuthorInstitution();
            Reference reference = authorInstitutionList.get(0);
            entryDto.setOrgId(getIdentifierValue(reference.getReference()));
            entryDto.setOrgName(getStringValue(reference.getDisplay()));
        }
        if (entryToStr) {
            entryDto.setJsonText(JSON.toJSONString(entry));
        }
        return entryDto;
    }

    /**
     * 文件夹
     *
     * @param folder
     * @return
     */
    private static DocumentFolderDto buildFolder(Folder folder) {
        DocumentFolderDto folderDto = new DocumentFolderDto();
        folderDto.setId(getIdValue(folder.getId()));
        folderDto.setHomeCommunityId(getOidValue(folder.getHomeCommunityId()));
        folderDto.setPatientDomain(getPatientIdValue(folder.getPatientId()));
        folderDto.setStatusCode(getStatusCodeValue(folder.getStatusCode()));
        folderDto.setUniqueId(getOidValue(folder.getUniqueId()));
        folderDto.setLastUpdateTime(dateTimeConvertDate(folder.getLastUpdateTime()));
        folderDto.setTypeCode(convertConceptList(folder.getTypeCode()));
        return folderDto;
    }


    private static List<RhinCodeableDto> convertConceptList(List<CodeableConcept> conceptList) {
        if (CollectionUtils.isEmpty(conceptList)) {
            return Collections.emptyList();
        }
        List<RhinCodeableDto> codingDtoList = new ArrayList<>();
        conceptList.forEach(concept -> codingDtoList.add(convertConcept(concept)));
        return codingDtoList;
    }

    private static RhinCodeableDto convertConcept(CodeableConcept concept) {
        if (Objects.nonNull(concept)) {
            RhinCodeableDto codeableDto = new RhinCodeableDto();
            codeableDto.setText(getStringValue(concept.getText()));
            List<Coding> codingList = concept.getCoding();
            if (!CollectionUtils.isEmpty(concept.getCoding())) {
                codeableDto.setCoding(codingList.stream().map(DocumentStorageAssembler::convertCoding).collect(Collectors.toList()));
            }
            return codeableDto;
        }
        return null;
    }

    private static RhinCodingDto convertCoding(Coding coding) {
        if (Objects.nonNull(coding)) {
            RhinCodingDto codingDto = new RhinCodingDto();
            codingDto.setCodeValue(getCodeValue(coding.getCode()));
            codingDto.setDisplayName(getStringValue(coding.getDisplay()));
            codingDto.setCodeSystem(getUriValue(coding.getSystem()));
            codingDto.setCodeSystemName(getStringValue(coding.getSystemName()));
            codingDto.setCodeVersion(getStringValue(coding.getVersion()));
            return codingDto;
        }
        return null;
    }

    private static String getUriValue(URI uri) {
        return Objects.nonNull(uri) ? uri.getValue() : "";
    }

    private static String getOidValue(OID oid) {
        return Objects.nonNull(oid) ? oid.getValue() : "";
    }

    private static String getCodeValue(Code code) {
        return Objects.nonNull(code) ? code.getValue() : "";
    }

    private static String getStringValue(cn.org.chiss.rhin._2015.base.String string) {
        return Objects.nonNull(string) ? string.getValue() : "";
    }

    private static String getIdentifierValue(Identifier identifier) {
        if (Objects.nonNull(identifier) && Objects.nonNull(identifier.getValue())) {
            return getIdValue(identifier.getValue());
        }
        return "";
    }

    private static String getIdValue(ID id) {
        return Objects.nonNull(id) ? id.getValue() : "";
    }

    private static java.lang.Integer getIntegerValue(Integer integer) {
        return Objects.nonNull(integer) ? integer.getValue() : null;
    }

    private static PatientDomainDto getPatientIdValue(Identifier identifier) {
        PatientDomainDto patientDomainDto = new PatientDomainDto();
        if (Objects.isNull(identifier)) {
            return patientDomainDto;
        }
        if (Objects.nonNull(identifier.getValue())) {
            patientDomainDto.setPatientId(identifier.getValue().getValue());
        }
        if (Objects.nonNull(identifier.getSystem())) {
            patientDomainDto.setAppid(identifier.getSystem().getValue());
        }
        return patientDomainDto;
    }

    private static String getStatusCodeValue(ObjectStatus objectStatus) {
        if (Objects.nonNull(objectStatus) && Objects.nonNull(objectStatus.getValue())) {
            Class<ObjectStatusPrimitive> primitiveClass = ObjectStatusPrimitive.class;
            Field[] fields = primitiveClass.getFields();
            for (Field field : fields) {
                String name = objectStatus.getValue().name();
                if (name.equals(field.getName())) {
                    return field.getAnnotation(XmlEnumValue.class).value();
                }
            }
        }
        return "";
    }

    private static String getAssociationStatusValue(AssociationStatus associationStatus) {
        if (Objects.nonNull(associationStatus) && Objects.nonNull(associationStatus.getValue())) {
            return associationStatus.getValue().value();
        }
        return "";
    }

    private static String getAssociationTypeValue(AssociationType associationType) {
        return Objects.nonNull(associationType) ? associationType.getValue() : "";
    }

    private static PatientInfoDto getPatientInfo(Patient patientInfo) {
        PatientInfoDto patientInfoDto = new PatientInfoDto();
        if (Objects.isNull(patientInfo)) {
            return patientInfoDto;
        }
        if (Objects.isNull(patientInfo.getAssignedPerson())) {
            return patientInfoDto;
        }
        Person person = patientInfo.getAssignedPerson();
        if (!CollectionUtils.isEmpty(person.getName())) {
            List<HumanName> nameList = person.getName();
            HumanName humanName = nameList.get(0);
            if (Objects.nonNull(humanName) && Objects.nonNull(humanName.getValue())) {
                patientInfoDto.setHuanZheXm(humanName.getValue());
            }
        }
        if (!CollectionUtils.isEmpty(person.getIdentifier())) {
            List<Identifier> identifierList = person.getIdentifier();
            Identifier identifier = identifierList.get(0);
            if (Objects.nonNull(identifier) && Objects.nonNull(identifier.getValue())) {
                patientInfoDto.setZhengJianHm(identifier.getValue().getValue());
            }
        }
        return patientInfoDto;
    }

    private static java.util.Date dateTimeConvertDate(DateTime dateTime) {
        if (Objects.nonNull(dateTime) && Objects.nonNull(dateTime.getValue())) {
            // @by wade.nie 减少Converter中的堆栈异常信息
            String dt = dateTime.getValue();
            if(dt.length() <= DateFormatPatternConstants.D8.length()) {
                return Converter.toDate(dateTime.getValue(), DateFormatPatternConstants.D8);
            } else if(dt.length() <= DateFormatPatternConstants.D10.length()){
                return Converter.toDate(dateTime.getValue(), DateFormatPatternConstants.D10);
            } else if(dt.length() <= DateFormatPatternConstants.DT15.length()){
                return Converter.toDate(dateTime.getValue(), DateFormatPatternConstants.DT15);
            } else if (dt.length() <= DateFormatPatternConstants.DT19.length()) {
                return Converter.toDate(dateTime.getValue(), DateFormatPatternConstants.DT19);
            } else {
                return null;
            }
//            if(dateTime.getValue().length()>8){
//        		Date date =Converter.toDate(dateTime.getValue(), DateFormatPatternConstants.DT19);
//    			return date==null?Converter.toDate(dateTime.getValue(), DateFormatPatternConstants.DT15):date;
//        	}else{
//        		Date date =Converter.toDate(dateTime.getValue(), DateFormatPatternConstants.D8);
//    			return date==null?Converter.toDate(dateTime.getValue(), DateFormatPatternConstants.D10):date;
//        	}
        }
        return null;
    }
}
